package com.inifitness.sms.service.impl;

import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ThreadLocalRandom;
import java.util.stream.LongStream;

import com.aliyun.sdk.service.dysmsapi20170525.AsyncClient;
import com.aliyun.sdk.service.dysmsapi20170525.models.AddShortUrlRequest;
import com.aliyun.sdk.service.dysmsapi20170525.models.AddShortUrlResponse;
import com.aliyun.sdk.service.dysmsapi20170525.models.AddShortUrlResponseBody;
import com.aliyun.sdk.service.dysmsapi20170525.models.AddSmsSignRequest;
import com.aliyun.sdk.service.dysmsapi20170525.models.AddSmsSignResponse;
import com.aliyun.sdk.service.dysmsapi20170525.models.AddSmsSignResponseBody;
import com.aliyun.sdk.service.dysmsapi20170525.models.AddSmsTemplateRequest;
import com.aliyun.sdk.service.dysmsapi20170525.models.AddSmsTemplateResponse;
import com.aliyun.sdk.service.dysmsapi20170525.models.AddSmsTemplateResponseBody;
import com.aliyun.sdk.service.dysmsapi20170525.models.DeleteShortUrlRequest;
import com.aliyun.sdk.service.dysmsapi20170525.models.DeleteShortUrlResponse;
import com.aliyun.sdk.service.dysmsapi20170525.models.DeleteShortUrlResponseBody;
import com.aliyun.sdk.service.dysmsapi20170525.models.DeleteSmsSignRequest;
import com.aliyun.sdk.service.dysmsapi20170525.models.DeleteSmsSignResponse;
import com.aliyun.sdk.service.dysmsapi20170525.models.DeleteSmsSignResponseBody;
import com.aliyun.sdk.service.dysmsapi20170525.models.DeleteSmsTemplateRequest;
import com.aliyun.sdk.service.dysmsapi20170525.models.DeleteSmsTemplateResponse;
import com.aliyun.sdk.service.dysmsapi20170525.models.DeleteSmsTemplateResponseBody;
import com.aliyun.sdk.service.dysmsapi20170525.models.ModifySmsSignRequest;
import com.aliyun.sdk.service.dysmsapi20170525.models.ModifySmsSignResponse;
import com.aliyun.sdk.service.dysmsapi20170525.models.ModifySmsSignResponseBody;
import com.aliyun.sdk.service.dysmsapi20170525.models.ModifySmsTemplateRequest;
import com.aliyun.sdk.service.dysmsapi20170525.models.ModifySmsTemplateResponse;
import com.aliyun.sdk.service.dysmsapi20170525.models.ModifySmsTemplateResponseBody;
import com.aliyun.sdk.service.dysmsapi20170525.models.QuerySendStatisticsRequest;
import com.aliyun.sdk.service.dysmsapi20170525.models.QuerySendStatisticsResponse;
import com.aliyun.sdk.service.dysmsapi20170525.models.QuerySendStatisticsResponseBody;
import com.aliyun.sdk.service.dysmsapi20170525.models.QueryShortUrlRequest;
import com.aliyun.sdk.service.dysmsapi20170525.models.QueryShortUrlResponse;
import com.aliyun.sdk.service.dysmsapi20170525.models.QueryShortUrlResponseBody;
import com.aliyun.sdk.service.dysmsapi20170525.models.QuerySmsSignListRequest;
import com.aliyun.sdk.service.dysmsapi20170525.models.QuerySmsSignListResponse;
import com.aliyun.sdk.service.dysmsapi20170525.models.QuerySmsSignListResponseBody;
import com.aliyun.sdk.service.dysmsapi20170525.models.QuerySmsSignRequest;
import com.aliyun.sdk.service.dysmsapi20170525.models.QuerySmsSignResponse;
import com.aliyun.sdk.service.dysmsapi20170525.models.QuerySmsSignResponseBody;
import com.aliyun.sdk.service.dysmsapi20170525.models.QuerySmsTemplateListRequest;
import com.aliyun.sdk.service.dysmsapi20170525.models.QuerySmsTemplateListResponse;
import com.aliyun.sdk.service.dysmsapi20170525.models.QuerySmsTemplateListResponseBody;
import com.aliyun.sdk.service.dysmsapi20170525.models.QuerySmsTemplateRequest;
import com.aliyun.sdk.service.dysmsapi20170525.models.QuerySmsTemplateResponse;
import com.aliyun.sdk.service.dysmsapi20170525.models.QuerySmsTemplateResponseBody;
import com.aliyun.sdk.service.dysmsapi20170525.models.SendBatchSmsRequest;
import com.aliyun.sdk.service.dysmsapi20170525.models.SendBatchSmsResponse;
import com.aliyun.sdk.service.dysmsapi20170525.models.SendBatchSmsResponseBody;
import com.aliyun.sdk.service.dysmsapi20170525.models.SendSmsRequest;
import com.aliyun.sdk.service.dysmsapi20170525.models.SendSmsResponse;
import com.aliyun.sdk.service.dysmsapi20170525.models.SendSmsResponseBody;
import com.inifitness.sms.constants.SignSourceEnum;
import com.inifitness.sms.constants.SignTypeEnum;
import com.inifitness.sms.constants.TemplateTypeEnum;
import com.inifitness.sms.exceptions.AliSmsException;
import com.inifitness.sms.service.AliCloudSmsService;

import cn.hutool.json.JSONUtil;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.log4j.Log4j2;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.stereotype.Component;

/**
 * 阿里云短信服务类实现.
 *
 * @author mageric
 * @version 1.0.0
 * @since 2022/12/10 14:55
 */
@Component
@Log4j2
@RequiredArgsConstructor
@ConditionalOnProperty(value = "sms.type", havingValue = "aliyun")
public class AliCloudSmsServiceImpl implements AliCloudSmsService {

  private static final ThreadLocalRandom RANDOM = ThreadLocalRandom.current();
  private static final String SUCCESS_CODE = "OK";
  private static final String SUCCESS_MESSAGE = "OK";
  private static final String DEFAULT_REQUEST_ID = "0";
  private static final String DEFAULT_BIZ_ID = "0";
  private static final String DEFAULT_REMARK = "燧石SAAS服务平台为入驻平台的品牌和门店提供短信服务";
  private static final DateTimeFormatter SHORT_DATE_FORMATTER = DateTimeFormatter.ofPattern(
      "yyyyMMdd");
  private static final SignTypeEnum DEFAULT_SIGN_TYPE = SignTypeEnum.COMMON;
  private static final boolean DEBUG = true;
  private final AsyncClient asyncClient;

  /* **************************短信发送**************************** */

  /**
   * 发送单条短信.
   *
   * @param message      发送信息
   * @param templateCode 模板编码
   * @return 发送结果
   */
  @Override
  @SneakyThrows
  public SendSmsResponseBody sendSms(Message message, String templateCode) {
    log.debug(
        "发送短信:message.mobile={},message.signName={},message.parameters={},templateCode={},",
        message.getMobile(),
        message.getSignName(),
        message.getParameters().toString(),
        templateCode);

    if (DEBUG) {
      return SendSmsResponseBody.builder()
          .code(SUCCESS_CODE)
          .message(SUCCESS_MESSAGE)
          .requestId(DEFAULT_REQUEST_ID)
          .bizId(DEFAULT_BIZ_ID)
          .build();
    } else {
      SendSmsRequest sendSmsRequest = SendSmsRequest.builder()
          .phoneNumbers(message.getMobile())
          .signName(message.getSignName())
          .templateCode(templateCode)
          .templateParam(JSONUtil.toJsonStr(message.getParameters()))
          .build();

      log.debug("短信发送请求:{}", sendSmsRequest);
      CompletableFuture<SendSmsResponse> response = asyncClient.sendSms(sendSmsRequest);
      SendSmsResponse resp = response.get();
      log.debug("短信发送结果:{}", resp.toString());
      return Optional.ofNullable(resp.getBody())
          .filter(body -> SUCCESS_CODE.equals(body.getCode()))
          .orElseThrow(() -> new AliSmsException("发送短信失败"));
    }
  }

  /**
   * 批量发送短信.
   *
   * @param messages     发送信息
   * @param templateCode 模板编码
   * @return 发送结果
   */
  @Override
  @SneakyThrows
  public SendBatchSmsResponseBody sendBatchSms(Set<Message> messages, String templateCode) {
    log.info(
        "批量发送短信:phoneNumberJson={},signNameJson={},templateParamJson={},templateCode={},",
        JSONUtil.toJsonStr(messages.stream().map(Message::getMobile).toArray()),
        JSONUtil.toJsonStr(messages.stream().map(Message::getSignName).toArray()),
        JSONUtil.toJsonStr(messages.stream().map(Message::getParameters).toArray()),
        templateCode);

    if (DEBUG) {
      return SendBatchSmsResponseBody.builder()
          .code(SUCCESS_CODE)
          .message(SUCCESS_MESSAGE)
          .requestId(DEFAULT_REQUEST_ID)
          .bizId(DEFAULT_BIZ_ID)
          .build();
    } else {
      SendBatchSmsRequest sendBatchSmsRequest = SendBatchSmsRequest.builder()
          .templateCode(templateCode)
          .phoneNumberJson(JSONUtil.toJsonStr(messages.stream().map(Message::getMobile).toArray()))
          .signNameJson(JSONUtil.toJsonStr(messages.stream().map(Message::getSignName).toArray()))
          .templateParamJson(
              JSONUtil.toJsonStr(messages.stream().map(Message::getParameters).toArray()))
          .build();
      CompletableFuture<SendBatchSmsResponse> response = asyncClient.sendBatchSms(
          sendBatchSmsRequest);
      SendBatchSmsResponse resp = response.get();
      return Optional.ofNullable(resp.getBody())
          .filter(body -> SUCCESS_CODE.equals(body.getCode()))
          .orElseThrow(() -> new AliSmsException("发送短信失败"));
    }
  }

  /* **************************发送查询**************************** */

  /**
   * 查询短信发送统计信息.
   *
   * @param startDate 开始日期
   * @param endData   结束日期
   * @param pageIndex 当前页码
   * @param pageSize  每页显示的条数
   * @return 短信发送统计信息
   */
  @Override
  public QuerySendStatisticsResponseBody querySendStatistics(LocalDate startDate, LocalDate endData,
      Integer pageIndex, Integer pageSize) {
    return querySendStatistics(startDate, endData, pageIndex, pageSize, null, null);
  }

  /**
   * 查询短信发送统计信息.
   *
   * @param startDate    开始日期
   * @param endData      结束日期
   * @param pageIndex    当前页码
   * @param pageSize     每页显示的条数
   * @param templateType 模板类型
   * @return 短信发送统计信息
   */
  @Override
  public QuerySendStatisticsResponseBody querySendStatistics(LocalDate startDate, LocalDate endData,
      Integer pageIndex, Integer pageSize, TemplateTypeEnum templateType) {
    return querySendStatistics(startDate, endData, pageIndex, pageSize, templateType, null);
  }

  /**
   * 查询短信发送统计信息.
   *
   * @param startDate 开始日期
   * @param endData   结束日期
   * @param pageIndex 当前页码
   * @param pageSize  每页显示的条数
   * @param signName  签名名称
   * @return 短信发送统计信息
   */
  @Override
  public QuerySendStatisticsResponseBody querySendStatistics(LocalDate startDate, LocalDate endData,
      Integer pageIndex, Integer pageSize, String signName) {
    return querySendStatistics(startDate, endData, pageIndex, pageSize, null, signName);
  }

  /**
   * 查询短信发送统计信息.
   *
   * @param startDate    开始日期
   * @param endDate      结束日期
   * @param pageIndex    当前页码
   * @param pageSize     每页显示的条数
   * @param templateType 模板类型
   * @param signName     签名名称
   * @return 短信发送统计信息
   */
  @Override
  @SneakyThrows
  public QuerySendStatisticsResponseBody querySendStatistics(LocalDate startDate, LocalDate endDate,
      Integer pageIndex, Integer pageSize, TemplateTypeEnum templateType, String signName) {
    Objects.requireNonNull(startDate);
    Objects.requireNonNull(endDate);
    log.info(
        "查询短信发送统计信息:startDate={},endDate={},pageIndex={},pageSize={},templateType={},signName={}",
        startDate.format(SHORT_DATE_FORMATTER),
        endDate.format(SHORT_DATE_FORMATTER),
        pageIndex,
        pageSize,
        Optional.ofNullable(templateType).map(TemplateTypeEnum::getCode).orElse(null),
        signName
    );

    if (DEBUG) {
      final long randomBound = 100L;
      final int randomSize = 3;
      final long totalDays = startDate.until(endDate).getDays() + 1L;
      final long daysToProcess = Math.min(totalDays, pageSize);

      List<QuerySendStatisticsResponseBody.TargetList> list = new ArrayList<>();
      for (int i = 0; i < daysToProcess; i++) {
        LocalDate currentDate = startDate.plusDays(i);
        long[] randomValues = LongStream.generate(() -> RANDOM.nextLong(randomBound))
            .limit(randomSize)
            .toArray();

        long totalCount = LongStream.of(randomValues).sum();

        // 添加到目标列表
        list.add(QuerySendStatisticsResponseBody.TargetList.builder()
            .totalCount(totalCount)
            .respondedSuccessCount(randomValues[0])
            .respondedFailCount(randomValues[1])
            .noRespondedCount(randomValues[2])
            .sendDate(currentDate.format(SHORT_DATE_FORMATTER))
            .build());
      }

      QuerySendStatisticsResponseBody.Data data = QuerySendStatisticsResponseBody.Data.builder()
          .totalSize(daysToProcess)
          .targetList(list)
          .build();

      return QuerySendStatisticsResponseBody.builder()
          .code(SUCCESS_CODE)
          .message(SUCCESS_MESSAGE)
          .requestId(DEFAULT_REQUEST_ID)
          .data(data)
          .build();
    } else {
      QuerySendStatisticsRequest.Builder builder = QuerySendStatisticsRequest.builder()
          //短信发送范围 1：国内短信发送记录 2：国际/港澳台短信发送记录。
          .isGlobe(1)
          .startDate(startDate.format(SHORT_DATE_FORMATTER))
          .endDate(endDate.format(SHORT_DATE_FORMATTER))
          .pageIndex(pageIndex)
          .pageSize(pageSize);

      builder.templateType(Optional.ofNullable(templateType)
          .map(TemplateTypeEnum::getCode)
          .orElse(null)
      );
      if (Objects.nonNull(signName)) {
        builder.signName(signName);
      }
      QuerySendStatisticsRequest querySendStatisticsRequest = builder.build();

      CompletableFuture<QuerySendStatisticsResponse> response = asyncClient.querySendStatistics(
          querySendStatisticsRequest);

      QuerySendStatisticsResponse resp = response.get();
      return Optional.ofNullable(resp.getBody())
          .filter(body -> SUCCESS_CODE.equals(body.getCode()))
          .orElseThrow(() -> new AliSmsException("查询短信发送统计信息失败"));
    }
  }

  /* **************************签名管理**************************** */

  /**
   * 申请短信签名.
   *
   * @param signName 短信签名
   * @param fileList 证明文件
   * @return 申请短信签名结果
   */
  @Override
  public AddSmsSignResponseBody addSmsSign(String signName,
      List<AddSmsSignRequest.SignFileList> fileList) {
    return addSmsSign(signName, SignSourceEnum.WEBSITE_NAME,
        DEFAULT_REMARK, DEFAULT_SIGN_TYPE, fileList);
  }

  /**
   * 申请短信签名.
   *
   * @param signName   短信签名
   * @param signSource 签名来源
   * @param remark     场景说明
   * @param fileList   证明文件
   * @return 申请短信签名结果
   */
  @Override
  public AddSmsSignResponseBody addSmsSign(String signName, SignSourceEnum signSource,
      String remark, List<AddSmsSignRequest.SignFileList> fileList) {
    return addSmsSign(signName, signSource, remark, DEFAULT_SIGN_TYPE, fileList);
  }

  /**
   * 申请短信签名.
   *
   * @param signName   短信签名
   * @param signSource 签名来源
   * @param remark     场景说明
   * @param signType   签名类型 0，验证码 1通用
   * @param fileList   证明文件
   * @return 申请短信签名结果
   */
  @Override
  @SneakyThrows
  public AddSmsSignResponseBody addSmsSign(String signName, SignSourceEnum signSource,
      String remark, SignTypeEnum signType, List<AddSmsSignRequest.SignFileList> fileList) {
    log.info("添加签名:signName={},signSource={},remark={},signType={},fileList={}",
        signName,
        signSource.getCode(),
        remark,
        Optional.ofNullable(signType).map(SignTypeEnum::getCode)
            .orElse(DEFAULT_SIGN_TYPE.getCode()),
        JSONUtil.toJsonStr(fileList));
    if (DEBUG) {
      return AddSmsSignResponseBody.builder()
          .code(SUCCESS_CODE)
          .message(SUCCESS_MESSAGE)
          .requestId(DEFAULT_REQUEST_ID)
          .signName(signName)
          .build();
    } else {
      Integer signTypeValue = Optional.ofNullable(signType)
          .map(SignTypeEnum::getCode)
          .orElse(DEFAULT_SIGN_TYPE.getCode());

      AddSmsSignRequest addSmsSignRequest = AddSmsSignRequest.builder()
          .signName(signName)
          .signSource(signSource.getCode())
          .remark(remark)
          .signFileList(fileList)
          .signType(signTypeValue)
          .build();

      CompletableFuture<AddSmsSignResponse> response = asyncClient.addSmsSign(addSmsSignRequest);

      AddSmsSignResponse resp = response.get();
      return Optional.ofNullable(resp.getBody())
          .filter(body -> SUCCESS_CODE.equals(body.getCode()))
          .orElseThrow(() -> new AliSmsException("添加签名失败"));
    }
  }

  /**
   * 删除短信签名.
   *
   * @param signName 短信签名
   * @return 删除短信签名结果
   */
  @Override
  @SneakyThrows
  public DeleteSmsSignResponseBody deleteSmsSign(String signName) {
    log.info("删除签名:signName={}", signName);

    if (DEBUG) {
      return DeleteSmsSignResponseBody.builder()
          .code(SUCCESS_CODE)
          .message(SUCCESS_MESSAGE)
          .requestId(DEFAULT_REQUEST_ID)
          .signName(signName)
          .build();
    } else {
      DeleteSmsSignRequest deleteSmsSignRequest = DeleteSmsSignRequest.builder()
          .signName(signName)
          .build();

      CompletableFuture<DeleteSmsSignResponse> response = asyncClient.deleteSmsSign(
          deleteSmsSignRequest);

      DeleteSmsSignResponse resp = response.get();
      return Optional.ofNullable(resp.getBody())
          .filter(body -> SUCCESS_CODE.equals(body.getCode()))
          .orElseThrow(() -> new AliSmsException("删除签名失败"));
    }
  }

  /**
   * 修改短信签名.
   *
   * @param signName 短信签名
   * @param fileList 证明文件
   * @return 修改短信签名结果
   */
  @Override
  public ModifySmsSignResponseBody modifySmsSign(String signName,
      List<ModifySmsSignRequest.SignFileList> fileList) {
    return modifySmsSign(signName, SignSourceEnum.WEBSITE_NAME,
        DEFAULT_REMARK, DEFAULT_SIGN_TYPE, fileList);
  }

  /**
   * 修改短信签名.
   *
   * @param signName   短信签名
   * @param signSource 签名来源
   * @param remark     场景说明
   * @param fileList   证明文件
   * @return 修改短信签名结果
   */
  @Override
  public ModifySmsSignResponseBody modifySmsSign(String signName, SignSourceEnum signSource,
      String remark, List<ModifySmsSignRequest.SignFileList> fileList) {
    return modifySmsSign(signName, signSource, remark, DEFAULT_SIGN_TYPE, fileList);
  }

  /**
   * 修改短信签名.
   *
   * @param signName   短信签名
   * @param signSource 签名来源
   * @param remark     场景说明
   * @param signType   签名类型 0，验证码 1通用
   * @param fileList   证明文件
   * @return 修改短信签名结果
   */
  @Override
  @SneakyThrows
  public ModifySmsSignResponseBody modifySmsSign(String signName, SignSourceEnum signSource,
      String remark, SignTypeEnum signType, List<ModifySmsSignRequest.SignFileList> fileList) {
    log.info("修改签名:signName={},signSource={},remark={},signType={},fileList={}",
        signName,
        signSource.getCode(),
        remark,
        Optional.ofNullable(signType).map(SignTypeEnum::getCode)
            .orElse(DEFAULT_SIGN_TYPE.getCode()),
        JSONUtil.toJsonStr(fileList));
    if (DEBUG) {
      return ModifySmsSignResponseBody.builder()
          .code(SUCCESS_CODE)
          .message(SUCCESS_MESSAGE)
          .requestId(DEFAULT_REQUEST_ID)
          .signName(signName)
          .build();
    } else {
      Integer signTypeValue = Optional.ofNullable(signType).map(SignTypeEnum::getCode)
          .orElse(DEFAULT_SIGN_TYPE.getCode());
      ModifySmsSignRequest modifySmsSignRequest = ModifySmsSignRequest.builder()
          .signName(signName)
          .signSource(signSource.getCode())
          .remark(remark)
          .signFileList(fileList)
          .signType(signTypeValue)
          .build();

      CompletableFuture<ModifySmsSignResponse> response = asyncClient.modifySmsSign(
          modifySmsSignRequest);

      ModifySmsSignResponse resp = response.get();
      return Optional.ofNullable(resp.getBody())
          .filter(body -> SUCCESS_CODE.equals(body.getCode()))
          .orElseThrow(() -> new AliSmsException("修改短信模板失败"));
    }
  }

  /**
   * 查询短信签名列表.
   *
   * @param pageIndex 页码
   * @param pageSize  每页显示数量
   * @return 短信签名列表
   */
  @Override
  @SneakyThrows
  public QuerySmsSignListResponseBody querySmsSignList(Integer pageIndex, Integer pageSize) {
    log.info("查询签名列表:pageIndex={},pageSize={}",
        pageIndex,
        pageSize);

    if (DEBUG) {
      final String defaultSignName = "测试";
      final String defaultAuditStatus = "AUDIT_STATE_PASS";
      final String defaultCreateDate = "2023-01-01 14:11:11";
      final String defaultRejectDate = "2023-01-01 15:21:13";
      final String defaultRejectInfo = "无审批备注";
      final String defaultBusinessType = "通用类型";

      List<QuerySmsSignListResponseBody.SmsSignList> smsSignList = new ArrayList<>();
      QuerySmsSignListResponseBody.SmsSignList signList = QuerySmsSignListResponseBody.SmsSignList.builder()
          .signName(defaultSignName)
          .auditStatus(defaultAuditStatus)
          .createDate(defaultCreateDate)
          .reason(QuerySmsSignListResponseBody.Reason.builder().rejectDate(defaultRejectDate)
              .rejectInfo(defaultRejectInfo).rejectSubInfo(defaultRejectInfo).build())
          .businessType(defaultBusinessType).build();
      smsSignList.add(signList);

      return QuerySmsSignListResponseBody.builder()
          .code(SUCCESS_CODE)
          .message(SUCCESS_MESSAGE)
          .requestId(DEFAULT_REQUEST_ID)
          .totalCount(1L).smsSignList(smsSignList).build();
    } else {
      QuerySmsSignListRequest querySmsSignListRequest = QuerySmsSignListRequest.builder()
          .pageIndex(pageIndex)
          .pageSize(pageSize)
          .build();

      CompletableFuture<QuerySmsSignListResponse> response = asyncClient.querySmsSignList(
          querySmsSignListRequest);

      QuerySmsSignListResponse resp = response.get();
      return Optional.ofNullable(resp.getBody())
          .filter(body -> SUCCESS_CODE.equals(body.getCode()))
          .orElseThrow(() -> new AliSmsException("查询短信签名列表失败"));
    }
  }

  /**
   * 查询短信签名申请状态.
   *
   * @param signName 签名
   * @return 短信签名申请状态
   */
  @Override
  @SneakyThrows
  public QuerySmsSignResponseBody querySmsSign(String signName) {
    log.info("查询签名状态:signName={}", signName);

    if (DEBUG) {
      final int defaultSignStats = 1;
      return QuerySmsSignResponseBody.builder()
          .code(SUCCESS_CODE)
          .message(SUCCESS_MESSAGE)
          .requestId(DEFAULT_REQUEST_ID)
          .signName(signName)
          .signStatus(defaultSignStats)
          .build();
    } else {
      QuerySmsSignRequest querySmsSignRequest = QuerySmsSignRequest.builder()
          .signName(signName)
          .build();

      CompletableFuture<QuerySmsSignResponse> response = asyncClient.querySmsSign(
          querySmsSignRequest);

      QuerySmsSignResponse resp = response.get();
      return Optional.ofNullable(resp.getBody())
          .filter(body -> SUCCESS_CODE.equals(body.getCode()))
          .orElseThrow(() -> new AliSmsException("查询短信签名失败"));
    }
  }

  /* **************************模板管理**************************** */

  /**
   * 添加短信模板.
   *
   * @param templateType    模板类型
   * @param templateName    模板名称
   * @param templateContent 模板内容
   * @param remark          场景模板
   * @return 短信模板添加结果
   */
  @Override
  @SneakyThrows
  public AddSmsTemplateResponseBody addSmsTemplate(TemplateTypeEnum templateType,
      String templateName, String templateContent, String remark) {
    log.info("添加短信模板:templateType={},templateName={},templateContent={},remark={}",
        templateType.getCode(), templateName,
        templateContent, remark);

    if (DEBUG) {
      final String defaultTemplateCode = "0";
      return AddSmsTemplateResponseBody.builder()
          .code(SUCCESS_CODE)
          .message(SUCCESS_MESSAGE)
          .requestId(DEFAULT_REQUEST_ID)
          .templateCode(defaultTemplateCode).build();
    } else {
      AddSmsTemplateRequest addSmsTemplateRequest = AddSmsTemplateRequest.builder()
          .templateType(templateType.getCode())
          .templateName(templateName)
          .templateContent(templateContent)
          .remark(remark)
          .build();

      CompletableFuture<AddSmsTemplateResponse> response = asyncClient.addSmsTemplate(
          addSmsTemplateRequest);
      AddSmsTemplateResponse resp = response.get();
      return Optional.ofNullable(resp.getBody())
          .filter(body -> SUCCESS_CODE.equals(body.getCode()))
          .orElseThrow(() -> new AliSmsException("添加短信模板失败"));
    }
  }

  /**
   * 删除模板.
   *
   * @param templateCode 模板编码
   * @return 删除模板结果
   */
  @Override
  @SneakyThrows
  public DeleteSmsTemplateResponseBody deleteSmsTemplate(String templateCode) {
    log.info("删除短信模板:templateCode={}", templateCode);
    if (DEBUG) {
      return DeleteSmsTemplateResponseBody.builder()
          .code(SUCCESS_CODE)
          .message(SUCCESS_MESSAGE)
          .requestId(DEFAULT_REQUEST_ID)
          .templateCode(templateCode)
          .build();
    } else {
      DeleteSmsTemplateRequest deleteSmsTemplateRequest = DeleteSmsTemplateRequest.builder()
          .templateCode(templateCode)
          .build();
      CompletableFuture<DeleteSmsTemplateResponse> response = asyncClient.deleteSmsTemplate(
          deleteSmsTemplateRequest);
      DeleteSmsTemplateResponse resp = response.get();
      return Optional.ofNullable(resp.getBody())
          .filter(body -> SUCCESS_CODE.equals(body.getCode()))
          .orElseThrow(() -> new AliSmsException("删除短信模板失败"));
    }
  }

  /**
   * 修改模板.
   *
   * @param templateCode    模板编码
   * @param templateType    买本类型
   * @param templateName    模板名称
   * @param templateContent 模板内容
   * @param remark          场景说明
   * @return 修改模板结果
   */
  @Override
  @SneakyThrows
  public ModifySmsTemplateResponseBody modifySmsTemplate(String templateCode,
      TemplateTypeEnum templateType, String templateName, String templateContent, String remark) {
    log.info("修改短信模板:templateType={},templateName={},templateContent={},remark={}",
        templateType.getCode(),
        templateName,
        templateContent, remark);

    if (DEBUG) {
      return ModifySmsTemplateResponseBody.builder()
          .code(SUCCESS_CODE)
          .message(SUCCESS_MESSAGE)
          .requestId(DEFAULT_REQUEST_ID)
          .templateCode("0").build();
    } else {
      ModifySmsTemplateRequest addSmsTemplateRequest = ModifySmsTemplateRequest.builder()
          .templateCode(templateCode)
          .templateType(templateType.getCode())
          .templateName(templateName)
          .templateContent(templateContent)
          .remark(remark)
          .build();

      CompletableFuture<ModifySmsTemplateResponse> response = asyncClient.modifySmsTemplate(
          addSmsTemplateRequest);
      ModifySmsTemplateResponse resp = response.get();
      return Optional.ofNullable(resp.getBody())
          .filter(body -> SUCCESS_CODE.equals(body.getCode()))
          .orElseThrow(() -> new AliSmsException("修改短信模板失败"));
    }
  }

  /**
   * 查询短信模板列表详情.
   *
   * @param pageIndex 页码
   * @param pageSize  每页显示数量
   * @return 短信模板列表详情
   */
  @Override
  @SneakyThrows
  public QuerySmsTemplateListResponseBody querySmsTemplateList(Integer pageIndex,
      final Integer pageSize) {
    log.info("查询短信模板列表:pageIndex={},pageSize={}", pageIndex, pageSize);
    if (DEBUG) {
      final String defaultTemplateName = "测试模板";
      final String defaultTemplateCode = "0";
      final String defaultTemplateContent = "123456789";
      final String defaultAuditStatus = "AUDIT_STATE_PASS";
      final String defaultCreateDate = "2023-01-01 12:11:11";
      final String defaultRejectDate = "2023-01-01 13:22:13";
      final String defaultRejectInfo = "无审批备注";
      final String defaultOderId = "0";
      final int defaultTemplateType = 7;

      QuerySmsTemplateListResponseBody.Reason reason = QuerySmsTemplateListResponseBody.Reason.builder()
          .rejectDate(defaultRejectDate)
          .rejectInfo(defaultRejectInfo)
          .rejectSubInfo(defaultRejectInfo)
          .build();

      List<QuerySmsTemplateListResponseBody.SmsTemplateList> smsTemplateList = new ArrayList<>();
      smsTemplateList.add(
          QuerySmsTemplateListResponseBody.SmsTemplateList.builder()
              .templateCode(defaultTemplateCode)
              .templateName(defaultTemplateName).outerTemplateType(0)
              .auditStatus(defaultAuditStatus)
              .templateContent(defaultTemplateContent)
              .createDate(defaultCreateDate)
              .reason(reason)
              .orderId(defaultOderId)
              .templateType(defaultTemplateType).build());

      return QuerySmsTemplateListResponseBody.builder()
          .code(SUCCESS_CODE)
          .message(SUCCESS_MESSAGE)
          .requestId(DEFAULT_REQUEST_ID)
          .smsTemplateList(smsTemplateList).build();
    } else {
      QuerySmsTemplateListRequest querySmsSignListRequest = QuerySmsTemplateListRequest.builder()
          .pageIndex(pageIndex)
          .pageSize(pageSize)
          .build();

      CompletableFuture<QuerySmsTemplateListResponse> response = asyncClient.querySmsTemplateList(
          querySmsSignListRequest);

      QuerySmsTemplateListResponse resp = response.get();
      return Optional.ofNullable(resp.getBody())
          .filter(body -> SUCCESS_CODE.equals(body.getCode()))
          .orElseThrow(() -> new AliSmsException("查询短信模板列表详情失败"));
    }
  }

  /**
   * 查询模板信息.
   *
   * @param templateCode 模板编码
   * @return 模板信息
   */
  @Override
  @SneakyThrows
  public QuerySmsTemplateResponseBody querySmsTemplate(String templateCode) {
    log.info("查询短信模板审核状态:templateCode={}", templateCode);
    if (DEBUG) {
      final String defaultTemplateName = "测试模板";
      final String defaultTemplateContent = "123456789";
      final String defaultCreateDate = "2023-01-01 13:11:11";

      return QuerySmsTemplateResponseBody.builder()
          .code(SUCCESS_CODE)
          .message(SUCCESS_MESSAGE)
          .requestId(DEFAULT_REQUEST_ID)
          .templateCode(templateCode)
          .templateName(defaultTemplateName)
          .templateContent(defaultTemplateContent)
          .createDate(defaultCreateDate)
          .build();
    } else {
      QuerySmsTemplateRequest querySmsTemplateRequest = QuerySmsTemplateRequest.builder()
          .templateCode(templateCode)
          .build();

      CompletableFuture<QuerySmsTemplateResponse> response = asyncClient.querySmsTemplate(
          querySmsTemplateRequest);
      QuerySmsTemplateResponse resp = response.get();
      return Optional.ofNullable(resp.getBody())
          .filter(body -> SUCCESS_CODE.equals(body.getCode()))
          .orElseThrow(() -> new AliSmsException("查询短信模板失败"));
    }
  }

  /* **************************短链管理**************************** */

  /**
   * 创建短链.
   *
   * @param sourceUrl     原始链接地址
   * @param shortUrlName  短链服务名称
   * @param effectiveDays 短链服务使用有效期
   * @return 创建短链结果
   */
  @Override
  @SneakyThrows
  public AddShortUrlResponseBody addShortUrl(String sourceUrl, String shortUrlName,
      Integer effectiveDays) {
    log.info("添加短链:sourceUrl={},shortUrlName={},effectiveDays={}", sourceUrl, shortUrlName,
        effectiveDays);

    if (DEBUG) {
      final String defaultShortUrl = "https://t.cn/JnkjNDOns";
      final String defaultExpireDate = "2024-09-19 00:00:00";
      AddShortUrlResponseBody.Data data = AddShortUrlResponseBody.Data.builder()
          .sourceUrl(sourceUrl)
          .shortUrl(defaultShortUrl)
          .expireDate(defaultExpireDate)
          .build();
      return AddShortUrlResponseBody.builder()
          .code(SUCCESS_CODE)
          .message(SUCCESS_MESSAGE)
          .requestId(DEFAULT_REQUEST_ID)
          .data(data)
          .build();
    } else {
      AddShortUrlRequest addShortUrlRequest = AddShortUrlRequest.builder()
          .sourceUrl(sourceUrl)
          .shortUrlName(shortUrlName)
          .effectiveDays(String.valueOf(effectiveDays))
          .build();

      CompletableFuture<AddShortUrlResponse> response = asyncClient.addShortUrl(addShortUrlRequest);
      AddShortUrlResponse resp = response.get();
      return Optional.ofNullable(resp.getBody())
          .filter(body -> SUCCESS_CODE.equals(body.getCode()))
          .orElseThrow(() -> new AliSmsException("创建短链失败"));
    }
  }

  /**
   * 删除短链 删除后短链将无法使用，无法还原为原链.
   *
   * @param sourceUrl 原链
   * @return 删除短链结果
   */
  @Override
  @SneakyThrows
  public DeleteShortUrlResponseBody deleteShortUrl(String sourceUrl) {
    log.info("删除短链:sourceUrl={}", sourceUrl);

    if (DEBUG) {
      return DeleteShortUrlResponseBody.builder()
          .code(SUCCESS_CODE)
          .message(SUCCESS_MESSAGE)
          .requestId(DEFAULT_REQUEST_ID)
          .build();
    } else {
      DeleteShortUrlRequest deleteShortUrlRequest = DeleteShortUrlRequest.builder()
          .sourceUrl(sourceUrl)
          .build();

      CompletableFuture<DeleteShortUrlResponse> response = asyncClient.deleteShortUrl(
          deleteShortUrlRequest);
      DeleteShortUrlResponse resp = response.get();
      return Optional.ofNullable(resp.getBody())
          .filter(body -> SUCCESS_CODE.equals(body.getCode()))
          .orElseThrow(() -> new AliSmsException("删除短链失败"));
    }
  }

  /**
   * 查询短链状态 可判断短链是否可用.
   *
   * @param shortUrl 生成的短链服务地址
   * @return 短链状态
   */
  @Override
  @SneakyThrows
  public QueryShortUrlResponseBody queryShortUrl(String shortUrl) {
    log.info("查询短链:shortUrl={}", shortUrl);
    if (DEBUG) {
      final String defaultSourceUrl = "https://www.baidu.com";
      final String defaultShortUrl = "https://t.cn/JnkjNDOns";
      final String defaultExpireDate = "2023-09-19 00:00:00";
      final String defaultPageViewCount = "300";
      final String defaultShortUrlStatus = "expired";
      final String defaultCreateDate = "2019-01-08 16:44:13";
      final String defaultUniqueVisitorCount = "23";
      QueryShortUrlResponseBody.Data data = QueryShortUrlResponseBody.Data.builder()
          .sourceUrl(defaultSourceUrl)
          .shortUrl(defaultShortUrl).expireDate(defaultExpireDate)
          .pageViewCount(defaultPageViewCount)
          .shortUrlStatus(defaultShortUrlStatus)
          .createDate(defaultCreateDate)
          .uniqueVisitorCount(defaultUniqueVisitorCount)
          .build();

      return QueryShortUrlResponseBody.builder()
          .code(SUCCESS_CODE)
          .message(SUCCESS_MESSAGE)
          .requestId(DEFAULT_REQUEST_ID)
          .data(data)
          .build();
    } else {
      QueryShortUrlRequest queryShortUrlRequest = QueryShortUrlRequest.builder()
          .shortUrl(shortUrl)
          .build();

      CompletableFuture<QueryShortUrlResponse> response = asyncClient.queryShortUrl(
          queryShortUrlRequest);
      QueryShortUrlResponse resp = response.get();
      return Optional.ofNullable(resp.getBody())
          .filter(body -> SUCCESS_CODE.equals(body.getCode()))
          .orElseThrow(() -> new AliSmsException("查询短链状态失败"));
    }
  }
}
